package org.twiky;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

/**
 * <p>
 * This is the example of one tips to updating widget through {@link AppWidgetManager#updateAppWidget(int, RemoteViews).
 * </p>
 * The widget will become unresponsive when the mobile device configuration changes. For example,
 * <p>
 * When the display mode change from portrait to landscape. 
 * </p> 
 * 
 * @author twinsen.tsang
 */
public class TestWidget extends AppWidgetProvider {

	/* The tag for logging */
	public static final String LOG_TAG = "TWIKY-WIDGET";
	
	/* The intent action */
	public static final String ACTION_TEST_CLICK = "org.twiky.test.click";

	/* The map containing the thread for updating the widget */
	private static final Map<Integer, Thread> g_hThreadMap = new HashMap<Integer, Thread>();
	
	/* (non-JAVADOC)
	 * @see android.appwidget.AppWidgetProvider#onReceive(android.content.Context, android.content.Intent)
	 */
	@Override
	public void onReceive(
		final Context ctx, 
		final Intent intent)
	{
		Log.d(LOG_TAG, "#onReceive: " + intent);
		
		super.onReceive(ctx, intent);
		String sAction = intent.getAction();
		if (sAction.equals(ACTION_TEST_CLICK)){
			/* This indicate the pending intent works fine when we are able
			 * to receive the expected intent.  
			 */
			Log.d(LOG_TAG, "Button clicked [logcat] ");
			Toast.makeText(ctx, "Button clicked [pendeing intent]", 100).show();
		}
	}
	
	/* (non-JAVADOC)
	 * @see android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[])
	 */
	@Override
	public void onUpdate(
		final Context ctx, 
		final AppWidgetManager appWidgetManager,
		final int[] aiAppWidgetIds)
	{
		Log.d(LOG_TAG, "#onUpdate: " + Arrays.toString(aiAppWidgetIds));
		
		super.onUpdate(ctx, appWidgetManager, aiAppWidgetIds);				
		final String sPackageName = ctx.getPackageName();
		
		/* Connect remote view */
		RemoteViews oRemoteViews = new RemoteViews(sPackageName, R.layout.widget);
		
		/* Pending intent on-click */
		oRemoteViews.setOnClickPendingIntent(R.id.btn_test, 
			this.createOnClickPendingIntent(ctx));
		
		for (int iAppWidgetId: aiAppWidgetIds){
			/* Update the remote views */
			appWidgetManager.updateAppWidget(iAppWidgetId, oRemoteViews);
			
			/* Spawn a thread for updating the widget views. 
			 * Note that [We don't create any pending intent again to the target view].
			 */
			final int iAppWidgetIdF = iAppWidgetId;
			Thread oThread = new Thread(
				new Runnable(){
					private int m_iCount;					
					private final Random m_oSeed = new Random();
					
					public void run(){
						try {
							while(true){
								RemoteViews oRemoteViews = new RemoteViews(ctx.getPackageName(), R.layout.widget);
								
								/* Once un-comment the following code, the widget
								 * will always responds correctly when you click
								 * on the button.
								 */						
								//oRemoteViews.setOnClickPendingIntent(R.id.btn_test, createOnClickPendingIntent(ctx));
								
								oRemoteViews.setTextViewText(
									R.id.btn_test, String.valueOf(this.m_oSeed.nextInt(100)));
								Log.d(LOG_TAG, "Updating the remote views: " + iAppWidgetIdF + " count:" + this.m_iCount);
								Thread.sleep(2000);						
								appWidgetManager.updateAppWidget(iAppWidgetIdF, oRemoteViews);
								this.m_iCount++;
							}
						} catch (InterruptedException iex){
							iex.printStackTrace();							
						}
					}
				}
			);
			oThread.start();
			g_hThreadMap.put(iAppWidgetId, oThread);  
		}	
	}
	
	PendingIntent createOnClickPendingIntent(final Context ctx){
		/* Make target intent */
		Intent intentTest = new Intent();
		intentTest.setAction(ACTION_TEST_CLICK);
		/* Make pending intent */
		PendingIntent pendingIntentTest = PendingIntent.getBroadcast(ctx, 0, intentTest, 0);
		return pendingIntentTest;
	}
	
	/* (non-JAVADOC)
	 * @see android.appwidget.AppWidgetProvider#onDeleted(android.content.Context, int[])
	 */
	@Override
	public void onDeleted(
		final Context ctx, 
		final int[] aiAppWidgetIds)
	{
		super.onDeleted(ctx, aiAppWidgetIds);
		/* clean up all thread to prevent memory leak */
		for (int iAppWidgetId: aiAppWidgetIds){
			Thread oThread = g_hThreadMap.remove(iAppWidgetId);
			if (oThread != null){
				oThread.interrupt();
			}
		}
	}
}